/** 
* @author:huyn 
* @version 创建时间：2019年3月1日 上午10:01:06 
* @Des:
* 	此时死锁产生。(参考ThreadDeadLockAndSolutions.java)
* 	为了解决这个问题，我们不使用显示的去锁，我们用信号量去控制。
* 	信号量可以控制资源能被多少线程访问，这里我们指定只能被一个线程访问，就做到了类似锁住。而信号量可以指定去获取的超时时间，我们可以根据这个超时时间，去做一个额外处理。
* 	对于无法成功获取的情况，一般就是重复尝试，或指定尝试的次数，也可以马上退出。
*/ 

package com.meego.cainiao.thread;

import java.util.Date;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class ThreadUnlockTestDemo {
//	public static String obj1 = "obj1";
	public static final Semaphore a1 = new Semaphore(1);
//	public static String obj2 = "obj2";
	public static final Semaphore a2 = new Semaphore(1);

	public static void main(String[] args) {
		LockAa la = new LockAa();
		new Thread(la).start();
		LockBb lb = new LockBb();
		new Thread(lb).start();
	}

}

class LockAa implements Runnable{
	public void run() {
		try {
			System.out.println(new Date().toString() + " LockAa 开始执行");
			while(true) {
				if(ThreadUnlockTestDemo.a1.tryAcquire(1, TimeUnit.SECONDS)) {
					System.out.println(new Date().toString() + " LockA 锁住 obj1");
					if(ThreadUnlockTestDemo.a2.tryAcquire(1, TimeUnit.SECONDS)) {
						System.out.println(new Date().toString() + " LockA 锁住 obj2");
						Thread.sleep(60 * 1000); // do something
					}
					else {
						System.out.println(new Date().toString() + "LockA 锁 obj2 失败");
					}
				}
				else {
					System.out.println(new Date().toString() + " LockA 锁 obj1 失败");
				}
				ThreadUnlockTestDemo.a1.release(); // 释放
				ThreadUnlockTestDemo.a2.release();
	            Thread.sleep(1000); // 马上进行尝试，现实情况下do something是不确定的
			}
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}
}


class LockBb implements Runnable{
	public void run() {
		try {
			System.out.println(new Date().toString() + " LockBb 开始执行");
			while(true) {
				if(ThreadUnlockTestDemo.a1.tryAcquire(1, TimeUnit.SECONDS)) {
					System.out.println(new Date().toString() + " LockBb 锁住 obj2");
					if(ThreadUnlockTestDemo.a2.tryAcquire(1, TimeUnit.SECONDS)) {
						System.out.println(new Date().toString() + " LockBb 锁住 obj1");
						Thread.sleep(60 * 1000); // do something
					}
					else {
						System.out.println(new Date().toString() + " LockBb 锁 obj1 失败");
					}
				}
				else {
					System.out.println(new Date().toString() + " LockBb 锁 obj2 失败");
				}
				ThreadUnlockTestDemo.a1.release(); // 释放
				ThreadUnlockTestDemo.a2.release();
	            Thread.sleep(1000); // 这里只是为了演示，所以tryAcquire只用1秒，而且B要给A让出能执行的时间，否则两个永远是死锁
			}
		}
		catch(Exception e) {
			e.printStackTrace();
		}
	}
}

